#include "netclient.h"
#include"../model/data.h"
#include"../model/datacenter.h"
#include"../toast.h"

#include<QNetworkReply>

namespace network{
NetClient::NetClient(model::DataCenter *dataCenter)
    :dataCenter(dataCenter)
{
    //不应该在这个环节初始化websocket,放到MainWidget初始化的时候
    //initWebsocket();
}

void NetClient::ping()
{
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + "/ping"));

    QNetworkReply* httpResp = httpClient.get(httpReq);
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //这里面，说明响应已经回来了
        if(httpResp->error() != QNetworkReply::NoError){
            //请求失败
            LOG() << "请求失败！" << httpResp->errorString();
            httpResp->deleteLater();
            return ;
        }
        //获取到响应的body
        QByteArray body = httpResp->readAll();
        LOG() << "响应内容:" << body;
        httpResp->deleteLater();
    });

}

/////////////////////////////////////////////////////////////////////////////////
/// 下列逻辑都是 websocket 相关的操作
/////////////////////////////////////////////////////////////////////////////////

void NetClient::initWebsocket()
{
    //1.准备好所有需要的信号槽
    //连接成功
    connect(&websocketClient,&QWebSocket::connected,this,[=](){
        LOG() << "websocket 连接成功！";
        //websocket连接成功之后发送身份认证消息！
        sendAuth();
    });

    //连接断开
    connect(&websocketClient,&QWebSocket::disconnected,this,[=](){
        LOG() << "websocket 连接断开！";
    });

    //连接出错
    connect(&websocketClient,&QWebSocket::errorOccurred,this,[=](QAbstractSocket::SocketError error){
        LOG() << "websocket 连接错误！" << error;
    });

    //收到文本消息！
    connect(&websocketClient,&QWebSocket::textMessageReceived,this,[=](const QString& message){
        LOG() << "websocket 收到文本消息！" << message;
    });

    //收到二进制消息
    connect(&websocketClient,&QWebSocket::binaryMessageReceived,this,[=](const QByteArray& byteArray){
        LOG() << "websocket 收到二进制消息！" << byteArray.length();
        bite_im::NotifyMessage notifyMessage;
        notifyMessage.deserialize(&serializer,byteArray);
        handleWsResponse(notifyMessage);
    });

    //2.和服务器建立真正的连接
    websocketClient.open(WEBSOCKET_URL);
}

void NetClient::handleWsResponse(const bite_im::NotifyMessage &notifyMessage)
{
    if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_MESSAGE_NOTIFY){
        //收到消息
        //1.把pb中的MessageInfo转换成客户端自己的Message
        model::Message message;
        message.load(notifyMessage.newMessageInfo().messageInfo());
        //2.针对自己的message做进一步处理
        handleWsMessage(message);
    }else if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY){
        //创建新的会话通知
        model::ChatSessionInfo chatSessionInfo;
        chatSessionInfo.load(notifyMessage.newChatSessionInfo().chatSessionInfo());
        handleWsSessionCreate(chatSessionInfo);

    }else if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY){
        //添加好友申请通知
        model::UserInfo userInfo;
        userInfo.load(notifyMessage.friendAddApply().userInfo());
        handleWsAddFriendApply(userInfo);
    }else if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY){
        //添加好友申请的处理结果
        model::UserInfo userInfo;
        userInfo.load(notifyMessage.friendProcessResult().userInfo());
        bool agree = notifyMessage.friendProcessResult().agree();
        handleWsAddFriendProcess(userInfo,agree);

    }else if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY){
        //删除好友通知
        const QString& userId = notifyMessage.friendRemove().userId();
        handleWsRemoveFriend(userId);

    }else{
        LOG() << "websocket发送通知类型错误!";
    }

}

void NetClient::handleWsMessage(const model::Message &message)
{
    //这里要考虑两个情况
    QList<model::Message>* messageList = dataCenter->getRecentMessageList(message.chatSessionId);
    if(messageList == nullptr){
        //1.如果当前这个消息所属的会话，里面的消息列表,没有在本地加载，此时就需要通过网络先加载整个消息列表
        connect(dataCenter,&model::DataCenter::getRecentMessageListDoneNoUI,this,&NetClient::receiveMessage,Qt::UniqueConnection);
        dataCenter->getRecentMessageListAsync(message.chatSessionId,false);
    }else{
        //2.如果当前这个消息所属的会话，里面的消息已经在本地加载了，直接把这个消息尾插到消息列表中即可
        messageList->push_back(message);
        this->receiveMessage(message.chatSessionId);
    }
}

void NetClient::handleWsRemoveFriend(const QString &userId)
{
    //1.通知用户哪个好友删除了自己
    model::UserInfo* userInfo = dataCenter->findFriendById(userId);
    const QString& nickname = userInfo->nickname;
    Toast::showMessage(nickname + "已将你从好友中删除!");
    //2.删除数据,DataCenter好友列表的数据
    dataCenter->removeFriend(userId);
    //2.通知界面变化、更新好友列表/会话列表
    emit dataCenter->deleteFriendDone();

}

void NetClient::handleWsAddFriendApply(const model::UserInfo &userInfo)
{
    //1.DataCenter 中有一个好友申请列表,需要把这个数据添加到好友申请列表中
    QList<model::UserInfo>* applyList = dataCenter->getApplyList();
    if(applyList == nullptr){
        LOG() << "客户端没有加载到好友申请列表!";
        return;
    }
    //把新元素放到列表前面
    applyList->push_front(userInfo);

    //2.通知界面更新
    emit dataCenter->receiveFriendApplyDone();
}

void NetClient::handleWsAddFriendProcess(const model::UserInfo &userInfo, bool agree)
{
    if(agree){
        //对方同意了你的好友申请
        QList<model::UserInfo>* friendList = dataCenter->getFriendList();
        if(friendList == nullptr){
            LOG() << "客户端没有加载好友列表";
            return;
        }
        friendList->push_front(userInfo);
    }

    emit dataCenter->receiveFriendProcessDone(userInfo.nickname,agree);
}

void NetClient::handleWsSessionCreate(const model::ChatSessionInfo &chatSessionInfo)
{
    //把这个ChatSessionInfo添加到会话列表中
    QList<model::ChatSessionInfo>* chatSessionList = dataCenter->getChatSessionList();
    if(chatSessionList == nullptr){
        LOG() << "客户端没有加载会话列表";
    }
    //新的元素添加到列表头部
    chatSessionList->push_front(chatSessionInfo);
    //发送一个信号,通知界面更新
    emit dataCenter->receiveSessionCreateDone();

}

void NetClient::sendAuth()
{
    bite_im::ClientAuthenticationReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(dataCenter->getLoginSessionId());

    QByteArray body = req.serialize(&serializer);

    websocketClient.sendBinaryMessage(body);

    LOG() << "[WS身份认证] requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId();
}


/////////////////////////////////////////////////////////////////////////////////
/// 下列逻辑都是 HTTP 相关的操作
/////////////////////////////////////////////////////////////////////////////////

const QString NetClient::makeRequestId()
{
    return "R" + QUuid::createUuid().toString().sliced(25,12);
}

//通过这个函数，把发送HTTP请求操作封装一下
QNetworkReply *NetClient::sendHttpRequest(const QString &apiPath, const QByteArray &body)
{
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + apiPath));
    httpReq.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-protobuf");

    QNetworkReply* httpResp = httpClient.post(httpReq,body);

    return httpResp;
}

//在这个函数内部，完成具体的网络通信即可
void NetClient::getMyself(const QString &loginSessionId)
{
    //1.构造出HTTP请求body的部分
    bite_im::GetUserInfoReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取个人信息]requestId" << req.requestId() << ",loginSessionId=" << loginSessionId;

    //2.构造出HTTP请求，并发送出去
    QNetworkReply* httpResp = sendHttpRequest("/service/user/get_user_info",body);

    //3.通过信号槽获取到当前的响应，finished 信号表示当前响应已经返回到客户端了。
    connect(httpResp,&QNetworkReply::finished,this,[=]{
        bool ok = false;
        QString reason;
        auto pbResp = handleHttpResponse<bite_im::GetUserInfoRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[获取个人信息]出错!requestId=" << req.requestId() << "reason=" << reason;
            return;
        }
        //c)把响应的数据保存到DataCenter中
        dataCenter->resetMyself(pbResp);

        //d)通知调用逻辑，响应已经处理完需要通过信号槽进行告知
        emit dataCenter->getMyselfDone();

        //e)打印日志
        LOG() << "[获取个人信息]处理响应requestId=" << req.requestId();
    });


}


void NetClient::getFriendList(const QString &loginSessionId)
{
    //1.通过protobuf 构造body
    bite_im::GetFriendListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取用户好友列表] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId;
    
    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/get_friend_list",body);
    
    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetFriendListRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[获取好友列表]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetFriendList(pbResp);

        //d)发送信号，通知界面，当前这个操作完成了
        emit dataCenter->getFriendListDone();

        //e)打印日志
        LOG() << "[获取好友列表]处理响应requestId=" << req.requestId();

    });
    
}

void NetClient::getChatSessionList(const QString &loginSessionId)
{
    //1.通过protobuf 构造body
    bite_im::GetChatSessionListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取用户会话列表] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/get_chat_session_list",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetChatSessionListRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[获取会话列表]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetChatSessionList(pbResp);

        //d)发送信号，通知界面，当前这个操作完成了
        emit dataCenter->getChatSessionListDone();

        //e)打印日志
        LOG() << "[获取会话列表]处理响应requestId=" << req.requestId();

    });

}

void NetClient::getApplyList(const QString &loginSessionId)
{
    //1.通过protobuf 构造body
    bite_im::GetChatSessionListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取用户好友申请列表] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/get_pending_friend_events",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetPendingFriendEventListRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[获取好友申请列表]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetApplyList(pbResp);

        //d)发送信号，通知界面，当前这个操作完成了
        emit dataCenter->getApplyListDone();

        //e)打印日志
        LOG() << "[获取好友列表]处理响应requestId=" << req.requestId();

    });


}

void NetClient::getRecentMessageList(const QString &loginSessionId, const QString &chatSessionId,bool updateUI)
{
    //1.通过protobuf 构造body
    bite_im::GetRecentMsgReq req;
    req.setRequestId(makeRequestId());
    req.setChatSessionId(chatSessionId);
    req.setSessionId(loginSessionId);
    req.setMsgCount(50);		//此处固定获取最近50条记录

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取最近消息列表] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId() << ", chatSessionId" << chatSessionId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/message_storage/get_recent",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetRecentMsgRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[获取最近消息列表]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetRecentMessageList(chatSessionId,pbResp);

        //d)发送信号，通知界面，当前这个操作完成了
        if(updateUI){
            emit dataCenter->getRecentMessageListDone(chatSessionId);
        }else{
            emit dataCenter->getRecentMessageListDoneNoUI(chatSessionId);
        }

        //e)打印日志
        LOG() << "[获取最近消息列表]处理响应requestId=" << req.requestId();

    });
}

//此处的extraInfo,可以用来传递"扩展信息",尤其对于文件消息来说，通过这个字段表示"文件名"
//其他类型的消息暂时不涉及,就直接设为""，如果后续有消息类型需要，都可以给这个参数服务一定的特殊含义
void NetClient::sendMessage(const QString &loginSessionId, const QString &chatSessionId, model::MessageType messageType,
                            const QByteArray &content,const QString& extraInfo)
{
    //1.通过protobuf构造body
    bite_im::NewMessageReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionId(chatSessionId);

    //LOG() << (messageType == model::MessageType::SPEECH_TYPE);

    //构造MessageContent
    bite_im::MessageContent messageContent;
    if(messageType == model::MessageType::TEXT_TYPE){
        messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::STRING);

        bite_im::StringMessageInfo stringMessageInfo;
        stringMessageInfo.setContent(content);
        messageContent.setStringMessage(stringMessageInfo);
    }else if(messageType == model::MessageType::IMAGE_TYPE){
        messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::IMAGE);

        bite_im::ImageMessageInfo imageMessageInfo;
        imageMessageInfo.setFileId(""); 	//fileId是文件在服务器存储的时候,生成的id,此时还无法获取到,暂时填成""
        imageMessageInfo.setImageContent(content);
        messageContent.setImageMessage(imageMessageInfo);
    }else if(messageType == model::MessageType::FILE_TYPE){
        messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::FILE);

        bite_im::FileMessageInfo fileMessageInfo;
        fileMessageInfo.setFileId("");		//fileId是文件在服务器存储的时候，生成的id,此时还无法获取到，暂时填成""
        fileMessageInfo.setFileSize(content.size());
        fileMessageInfo.setFileName(extraInfo);
        fileMessageInfo.setFileContents(content);
        messageContent.setFileMessage(fileMessageInfo);

    }else if(messageType == model::MessageType::SPEECH_TYPE){
        messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::SPEECH);

        bite_im::SpeechMessageInfo speechMessageInfo;
        speechMessageInfo.setFileId(""); 	//fileId是文件在服务器存储的时候,生成的id,此时还无法获取到,暂时填成""
        speechMessageInfo.setFileContents(content);
        messageContent.setSpeechMessage(speechMessageInfo);
    }else{
        LOG() << "错误的消息类型! messageType=" << messageType;
    }
    req.setMessage(messageContent);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[发送消息] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId
          << ", chatSessionId=" << req.chatSessionId() << ", messageType=" << req.message().messageType();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/message_transmit/new_message",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::NewMessageRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[发送消息]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)此处只需要记录"成功失败",不需要把内容写入到DataCenter中

        //d)发送信号，通知界面，当前这个操作完成了
        emit dataCenter->sendMessageDone(messageType,content,extraInfo);

        //e)打印日志
        LOG() << "[发送消息]处理响应requestId=" << req.requestId();
    });

}

void NetClient::receiveMessage(const QString &chatSessionId)
{
    //需要先判定一下，当前这个收到消息对应的会话，是否是正在被用户选中的"当前会话"
    //当前会话就需要把消息显示到消息展示区，也需要更新会话列表的消息预览
    //不是当前会话，只需要更新当前会话列表中的消息预览，并且更新"未读消息数目"
    if(chatSessionId == dataCenter->getCurrentChatSessionId()){
        //收到的消息会话，就是选中会话
        //在消息展示区，新增一个消息
        const model::Message& lastMessage = dataCenter->getRecentMessageList(chatSessionId)->back();
        emit dataCenter->receiveMessageDone(lastMessage);
    }else{
        //收到的消息会话，不是选中会话
        //更新未读消息数目
        dataCenter->addUnread(chatSessionId);
    }
    //统一更新会话列表的消息预览
    emit dataCenter->updateLastMessage(chatSessionId);

}

void NetClient::changeNickname(const QString &loginSessionId, const QString &nickname)
{
    //1.通过protobuf 构造body
    bite_im::SetUserNicknameReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setNickname(nickname);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[修改用户昵称] 发送请求requestId=" << req.requestId() << ", loginSessionId="<< loginSessionId
          << ", nickname=" << nickname;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/set_nickname",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SetUserAvatarRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[修改用户昵称]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetNickname(nickname);

        //d)发送信号，通知调用者完成
        emit dataCenter->changeNicknameDone();

        //e)打印日志
        LOG() << "[修改用户昵称]处理响应requestId=" << req.requestId();

    });

}

void NetClient::changeDescription(const QString &loginSessionId, const QString &desc)
{
    //1.通过protobuf 构造body
    bite_im::SetUserDescriptionReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setDescription(desc);
    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[修改用户签名] 发送请求requestId=" << req.requestId() << ", loginSessionId="<< loginSessionId
          << ", description=" << desc;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/set_description",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SetUserDescriptionRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[修改用户签名]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetDescription(desc);

        //d)发送信号，通知调用者完成
        emit dataCenter->changeDescriptionDone();

        //e)打印日志
        LOG() << "[修改用户签名]处理响应requestId=" << req.requestId();
    });


}

void NetClient::getVerifyCode(const QString &phone)
{
    //1.通过protobuf 构造body
    bite_im::PhoneVerifyCodeReq req;
    req.setRequestId(makeRequestId());
    req.setPhoneNumber(phone);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取手机验证码] 发送请求requestId=" << req.requestId() << ", phone=" << phone;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/get_phone_verify_code",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::PhoneVerifyCodeRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[获取手机验证码]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetVerifyCodeId(pbResp->verifyCodeId());

        //d)发送信号，通知调用者完成
        emit dataCenter->getVerifyCodeDone();

        //e)打印日志
        LOG() << "[获取手机验证码]处理响应requestId=" << req.requestId();
    });
}

void NetClient::changePhone(const QString &loginSessionId, const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    //1.通过protobuf 构造body
    bite_im::SetUserPhoneNumberReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setPhoneNumber(phone);
    req.setPhoneVerifyCodeId(verifyCodeId);
    req.setPhoneVerifyCode(verifyCode);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[修改手机号] 发送请求requestId=" << req.requestId() << ", phone=" << phone;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/set_phone",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SetUserPhoneNumberRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[修改手机号]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetPhone(phone);

        //d)发送信号，通知调用者完成
        emit dataCenter->changePhoneDone();

        //e)打印日志
        LOG() << "[修改手机完成]处理响应requestId=" << req.requestId();
    });

}

void NetClient::changeAvatar(const QString &loginSessionId, const QByteArray &avatar)
{
    //1.通过protobuf 构造body
    bite_im::SetUserAvatarReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setAvatar(avatar);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[修改头像] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/set_avatar",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SetUserAvatarRsp>(httpResp,&ok,&reason);

        //b)判断响应是否正确
        if(!ok){
            LOG() << "[修改头像]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果保存在DataCenter中
        dataCenter->resetAvatar(avatar);

        //d)发送信号，通知调用者完成
        emit dataCenter->changeAvatarDone();

        //e)打印日志
        LOG() << "[修改头像完成]处理响应requestId=" << req.requestId();
    });
}

void NetClient::deleteFriend(const QString &loginSessionId, const QString &userId)
{
    //1.通过protobuf 构造body
    bite_im::FriendRemoveReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setPeerId(userId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[删除好友] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", peerId=" << req.peerId();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/remove_friend",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendRemoveRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[删除好友]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果写入到DataCenter,把该删除的用户，从好友列表中，删除掉
        dataCenter->removeFriend(userId);


        //d)发送信号，通知调用这当前好友删除完毕
        emit dataCenter->deleteFriendDone();

        //e)打印日志
        LOG() << "[删除好友]响应完成requestId=" << req.requestId();

    });

}

void NetClient::addFriendApply(const QString &loginSessionId, const QString &userId)
{
    //1.通过protobuf 构造body
    bite_im::FriendAddReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setRespondentId(userId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[发送好友申请] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", userId=" << userId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/add_friend_apply",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendAddRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[发送好友申请]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果写入到DataCenter,此处不需要记录任何数据

        //d)发送信号，通知调用这当前好友删除完毕
        emit dataCenter->addFriendApplyDone();

        //e)打印日志
        LOG() << "[发送好友申请]响应完成requestId=" << req.requestId();

    });

}

void NetClient::acceptFriendApply(const QString &loginSessionId, const QString &userId)
{
    //1.通过protobuf 构造body
    bite_im::FriendAddProcessReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setAgree(true);
    req.setApplyUserId(userId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[同意好友申请] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", userId=" << req.applyUserId();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/add_friend_process",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendAddProcessRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[同意好友申请]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)此处做一个好友列表的更新
        //	一个是把数据从好友列表中删除掉
        //	另一个是吧好友申请列表中的这个数据添加到好友列表中
        model::UserInfo applyUser = dataCenter->removeFromApplyList(userId);
        QList<model::UserInfo>* friendList = dataCenter->getFriendList();
        friendList->push_front(applyUser);

        //d)发送信号，通知调用这当前好友删除完毕
        emit dataCenter->acceptFriendApplyDone();

        //e)打印日志
        LOG() << "[同意好友申请]响应完成requestId=" << req.requestId();
    });

}

void NetClient::rejectFriendApply(const QString &loginSessionId, const QString &userId)
{
    //1.通过protobuf 构造body
    bite_im::FriendAddProcessReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setAgree(true);
    req.setApplyUserId(userId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[拒绝好友申请] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", userId=" << req.applyUserId();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/add_friend_process",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendAddProcessRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[拒绝好友申请]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)此处做一个好友列表的更新,需要把这个记录从好友申请列表中删除掉
        dataCenter->removeFromApplyList(userId);

        //d)发送信号，通知调用这当前好友删除完毕
        emit dataCenter->rejectFriendApplyDone();

        //e)打印日志
        LOG() << "[拒绝好友申请]响应完成requestId=" << req.requestId();
    });

}

void NetClient::createGroupChatSession(const QString &loginSessionId, const QList<QString> &userIdList)
{
    //1.通过protobuf 构造body
    bite_im::ChatSessionCreateReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionName("新的群聊");
    req.setMemberIdList(userIdList);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[创建群聊会话] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", userIdList=" << userIdList;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/create_chat_session",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendAddProcessRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[创建群聊会话]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)由于此处创建好的会话是websocket推送过来的
        //在这里无需更新DataCenter，后续通过websocket的逻辑更新即可

        //d)通知调用者，响应处理完毕
        emit dataCenter->createGroupChatSessionDone();

        //e)打印日志
        LOG() << "[创建群聊会话]响应完成requestId=" << req.requestId();
    });


}

void NetClient::getMemberList(const QString &loginSessionId, const QString &chatSessionId)
{
    //1.通过protobuf 构造body
    bite_im::GetChatSessionMemberReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionId(chatSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取会话成员列表] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", chatSessionId=" << req.chatSessionId();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/get_chat_session_member",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetChatSessionMemberRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[获取会话成员列表]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetMemberList(chatSessionId,pbResp->memberInfoList());


        //d)通知调用者，响应处理完毕
        emit dataCenter->getMemberListDone(chatSessionId);

        //e)打印日志
        LOG() << "[获取会话成员列表]响应完成requestId=" << req.requestId();
    });

}

void NetClient::changeGroupName(const QString &loginSessionId, const QString &chatSessionId, const QString &groupName)
{
    //1.通过protobuf 构造body
    bite_im::SetGroupNameReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setGroupname(groupName);
    req.setChatSessionId(chatSessionId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[修改群聊名称] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", groupname=" << groupName;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/group/set_name",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SetGroupNameRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[修改群聊名称]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetGroupName(chatSessionId,groupName);

        //d)通知调用者，响应处理完毕
        emit dataCenter->changeGroupNameDone(chatSessionId);

        //e)打印日志
        LOG() << "[修改群聊名称]响应完成requestId=" << req.requestId();
    });
}

void NetClient::searchUser(const QString &loginSessionId, const QString &searchkey)
{
    //1.通过protobuf 构造body
    bite_im::FriendSearchReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setSearchKey(searchkey);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[搜索用户] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", searchkey=" << searchkey;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/friend/search_friend",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::FriendSearchRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[搜索用户]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetSearchUserResult(pbResp->userInfo());

        //d)通知调用者，响应处理完毕
        emit dataCenter->searchUserDone();

        //e)打印日志
        LOG() << "[搜索用户]响应完成requestId=" << req.requestId();
    });

}

void NetClient::searchMessageByTime(const QString &loginSessionId, const QString &chatSessionId, const QDateTime &begTime, const QDateTime &endTime)
{
    //1.通过protobuf 构造body
    bite_im::GetHistoryMsgReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionId(chatSessionId);
    req.setOverTime(begTime.toSecsSinceEpoch());
    req.setOverTime(endTime.toSecsSinceEpoch());

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[按时间搜索历史消息] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", chatSessionId=" << req.chatSessionId() << ", begTime=" << begTime << ", endTime=" << endTime;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/message_storage/get_history",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetHistoryMsgRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[按时间搜索历史消息]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetSearchMessageResult(pbResp->msgList());

        //d)通知调用者，响应处理完毕
        emit dataCenter->searchMessageDone();

        //e)打印日志
        LOG() << "[按时间搜索历史消息]响应完成requestId=" << pbResp->requestId();
    });

}

void NetClient::userLogin(const QString &username, const QString &password)
{
    //1.通过protobuf 构造body
    bite_im::UserLoginReq req;
    req.setRequestId(makeRequestId());
    req.setNickname(username);
    req.setPassword(password);
    req.setVerifyCodeId("");
    req.setVerifyCode("");

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[用户名登录] 发送请求requestId=" << req.requestId() << ", username=" << req.nickname()
          << ", password=" << req.password();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/username_login",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::UserLoginRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[用户名登录]失败! requestId=" << req.requestId() << ", reason=" << reason;
            emit dataCenter->userLoginDone(false,reason);
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetLoginSessionId(pbResp->loginSessionId());

        //d)通知调用者，响应处理完毕
        emit dataCenter->userLoginDone(true,"");

        //e)打印日志
        LOG() << "[用户名登录]响应完成requestId=" << pbResp->requestId();
    });

}

void NetClient::userRegister(const QString &username, const QString &password)
{
    //1.通过protobuf 构造body
    bite_im::UserRegisterReq req;
    req.setRequestId(makeRequestId());
    req.setNickname(username);
    req.setPassword(password);
    req.setVerifyCodeId("");
    req.setVerifyCode("");

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[用户名注册] 发送请求requestId=" << req.requestId() << ", username=" << req.nickname()
          << ", password=" << req.password();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/username_login",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::UserRegisterRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[用户名登录]失败! requestId=" << req.requestId() << ", reason=" << reason;
            emit dataCenter->userRegisterDone(false,reason);
            return;
        }

        //c)把结果记录到DataCenter
        //对于注册来说，不需要保存任何信息，直接跳过这个环节

        //d)通知调用者，响应处理完毕
        emit dataCenter->userRegisterDone(true,"");

        //e)打印日志
        LOG() << "[用户名注册]响应完成requestId=" << pbResp->requestId();
    });


}

void NetClient::phoneLogin(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    //1.通过protobuf 构造body
    bite_im::PhoneLoginReq req;
    req.setRequestId(makeRequestId());
    req.setPhoneNumber(phone);
    req.setVerifyCodeId("");
    req.setVerifyCode("");

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[手机号登录] 发送请求requestId=" << req.requestId() << ", phone=" << req.phoneNumber()
          << ", verifyCodeId=" << req.verifyCodeId() << ", verifyCode=" << req.verifyCode();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/phone_login",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::PhoneLoginRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[手机号登录]失败! requestId=" << req.requestId() << ", reason=" << reason;
            emit dataCenter->phoneLoginDone(false,reason);
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetLoginSessionId(pbResp->loginSessionId());

        //d)通知调用者，响应处理完毕
        emit dataCenter->phoneLoginDone(true,"");

        //e)打印日志
        LOG() << "[手机号登录]响应完成requestId=" << pbResp->requestId();
    });

}

void NetClient::phoneRegister(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    //1.通过protobuf 构造body
    bite_im::PhoneRegisterReq req;
    req.setRequestId(makeRequestId());
    req.setPhoneNumber(phone);
    req.setVerifyCodeId("");
    req.setVerifyCode("");

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[手机号注册] 发送请求requestId=" << req.requestId() << ", phone=" << req.phoneNumber()
          << ", verifyCodeId=" << req.verifyCodeId() << ", verifyCode=" << req.verifyCode();

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/user/phone_register",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::PhoneRegisterRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[手机号注册]失败! requestId=" << req.requestId() << ", reason=" << reason;
            emit dataCenter->phoneRegisterDone(false,reason);
            return;
        }

        //c)把结果记录到DataCenter,注册操作不需要记录

        //d)通知调用者，响应处理完毕
        emit dataCenter->phoneRegisterDone(true,"");

        //e)打印日志
        LOG() << "[手机号注册]响应完成requestId=" << pbResp->requestId();
    });

}

void NetClient::getSingleFile(const QString &loginSessionId, const QString &fileId)
{
    //1.通过protobuf 构造body
    bite_im::GetSingleFileReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setFileId(fileId);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[获取文件内容] 发送请求requestId=" << req.requestId() << ", fileId=" << fileId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/file/get_single_file",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::GetSingleFileRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[获取文件内容]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter,之前都是把结果保存到dataCenter的
        //这里涉及到的文件可能会很多，不使用DataCenter保存
        //直接通过信号把文件数据,投送到调用者的位置上

        //d)通知调用者，响应处理完毕
        emit dataCenter->getSingleFileDone(fileId,pbResp->fileData().fileContent());

        //e)打印日志
        LOG() << "[获取文件内容]响应完成requestId=" << pbResp->requestId();
    });

}

void NetClient::speechConvertText(const QString &loginSessionId, const QString &fileId, const QByteArray &content)
{
    //1.通过protobuf 构造body
    bite_im::SpeechRecognitionReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setSpeechContent(content);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[语音转文字] 发送请求requestId=" << req.requestId() << ", fileId=" << fileId;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/speech/recognition",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::SpeechRecognitionRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[语音转文字]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录写入到DataCenter中,此处不打算通过DataCenter表示这里的语音识别结果,直接通过信号通知结果即可


        //d)通知调用者，响应处理完毕
        emit dataCenter->speechConvertTextDone(fileId,pbResp->recognitionResult());

        //e)打印日志
        LOG() << "[语音转文字]响应完成requestId=" << pbResp->requestId();
    });


}

void NetClient::searchMessageByKey(const QString &loginSessionId, const QString &chatSessionId, const QString &searchKey)
{
    //1.通过protobuf 构造body
    bite_im::MsgSearchReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionId(chatSessionId);
    req.setSearchKey(searchKey);

    //序列化
    QByteArray body = req.serialize(&serializer);
    LOG() << "[按关键词搜索历史消息] 发送请求requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId()
          << ", chatSessionId=" << req.chatSessionId() << ", searchKey=" << searchKey;

    //2.发送HTTP请求
    QNetworkReply* httpResp = this->sendHttpRequest("/service/message_storage/search_history",body);

    //3.处理响应
    connect(httpResp,&QNetworkReply::finished,this,[=](){
        //a)解析响应
        bool ok = false;
        QString reason;
        auto pbResp = this->handleHttpResponse<bite_im::MsgSearchRsp>(httpResp,&ok,&reason);

        //判断响应是否正确
        if(!ok){
            LOG() << "[按关键词搜索历史消息]失败! requestId=" << req.requestId() << ", reason=" << reason;
            return;
        }

        //c)把结果记录到DataCenter
        dataCenter->resetSearchMessageResult(pbResp->msgList());

        //d)通知调用者，响应处理完毕
        emit dataCenter->searchMessageDone();

        //e)打印日志
        LOG() << "[按关键词搜索历史消息]响应完成requestId=" << pbResp->requestId();
    });

}

}//end network
















